package com.jacky.iot;

import org.eclipse.californium.core.CoapClient;
import org.eclipse.californium.core.CoapHandler;
import org.eclipse.californium.core.CoapObserveRelation;
import org.eclipse.californium.core.CoapResponse;
import org.eclipse.californium.core.coap.Request;
import org.eclipse.californium.core.config.CoapConfig;
import org.eclipse.californium.core.network.CoapEndpoint;
import org.eclipse.californium.core.network.Endpoint;
import org.eclipse.californium.elements.config.Configuration;
import org.eclipse.californium.elements.config.UdpConfig;
import org.eclipse.californium.elements.util.SslContextUtil;
import org.eclipse.californium.scandium.DTLSConnector;
import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
import org.eclipse.californium.scandium.dtls.CertificateType;
import org.eclipse.californium.scandium.dtls.x509.SingleCertificateProvider;
import org.eclipse.californium.scandium.dtls.x509.StaticNewAdvancedCertificateVerifier;

import java.io.File;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.cert.Certificate;
import java.util.concurrent.TimeUnit;

public class CoapDtlsClient {

    private static final File CONFIG_FILE = new File("Californium3.properties");
    private static final String CONFIG_HEADER = "Californium CoAP Properties file for client";
    private static final int DEFAULT_MAX_RESOURCE_SIZE = 2 * 1024 * 1024; // 2 MB
    private static final int DEFAULT_BLOCK_SIZE = 512;

    private static CoapClient client;

    static {
        CoapConfig.register();
        UdpConfig.register();
    }

    private static Configuration.DefinitionsProvider DEFAULTS = new Configuration.DefinitionsProvider() {

        @Override
        public void applyDefinitions(Configuration config) {
            config.set(CoapConfig.MAX_RESOURCE_BODY_SIZE, DEFAULT_MAX_RESOURCE_SIZE);
            config.set(CoapConfig.MAX_MESSAGE_SIZE, DEFAULT_BLOCK_SIZE);
            config.set(CoapConfig.PREFERRED_BLOCK_SIZE, DEFAULT_BLOCK_SIZE);
        }
    };

    public static void main(String[] args) throws GeneralSecurityException, IOException {
        Configuration config = Configuration.createWithFile(CONFIG_FILE, CONFIG_HEADER, DEFAULTS);
        Configuration.setStandard(config);
        Endpoint dtlsEndpoint = getDtlsEndpoint();
        client = new CoapClient("coaps://127.0.0.1:5684/obs");
        client.setEndpoint(dtlsEndpoint);

//        CoapDtlsClient coapDtlsClient = new CoapDtlsClient();
//        coapDtlsClient.observableTest(client);


        CoapObserveRelation relation = client.observe(new CoapHandler() {
            @Override
            public void onLoad(CoapResponse response) {
                System.out.println("observer got resp:" + response.getResponseText());
            }

            @Override
            public void onError() {

            }
        });
        try {
            TimeUnit.SECONDS.sleep(60);
        } catch (InterruptedException e) {
        }
        System.out.println("---------------\nCancel Observe");
        relation.reactiveCancel();
    }

    private void observableTest(CoapClient coapClient) {
//        Request req = Request.newGet();
//        req.setURI("coaps://127.0.0.1:5684/obs");
//        coapClient.advanced(new CoapHandler() {
//            @Override
//            public void onLoad(CoapResponse response) {
//                System.out.println("observer got resp:" + response.getResponseText());
//            }
//
//            @Override
//            public void onError() {
//
//            }
//        }, req);

        coapClient.setURI("coaps://127.0.0.1:5684/obs");
        CoapObserveRelation relation = coapClient.observe(new CoapHandler() {
            @Override
            public void onLoad(CoapResponse response) {
                System.out.println("observer got resp:" + response.getResponseText());
            }

            @Override
            public void onError() {

            }
        });
        try {
            TimeUnit.SECONDS.sleep(60);
        } catch (InterruptedException e) {
        }
        System.out.println("---------------\nCancel Observe");
        relation.reactiveCancel();
    }

    static Endpoint getDtlsEndpoint() throws GeneralSecurityException, IOException {
        SslContextUtil.Credentials clientCredentials = SslContextUtil.loadCredentials(
                SslContextUtil.CLASSPATH_SCHEME + "keystore.jks", "client", "keyPass".toCharArray(),
                "clientPass".toCharArray());
        Certificate[] trustedCertificates = SslContextUtil.loadTrustedCertificates(
                SslContextUtil.CLASSPATH_SCHEME + "trustStore.jks", "rootca", "trustPass".toCharArray());

        Configuration configuration = Configuration.createWithFile(Configuration.DEFAULT_FILE, "DTLS example client", DEFAULTS);

        DtlsConnectorConfig.Builder builder = DtlsConnectorConfig.builder(configuration);
//        builder.setPskStore(new SinglePskStore("Client_identity", "secretPSK".getBytes()));
        builder.setCertificateIdentityProvider(new SingleCertificateProvider(clientCredentials.getPrivateKey(), clientCredentials.getCertificateChain(),
                CertificateType.RAW_PUBLIC_KEY, CertificateType.X_509));
        builder.setCertificateIdentityProvider(new SingleCertificateProvider(
                clientCredentials.getPrivateKey(), clientCredentials.getCertificateChain(), CertificateType.RAW_PUBLIC_KEY,
                CertificateType.X_509
        )).setAdvancedCertificateVerifier(StaticNewAdvancedCertificateVerifier.builder()
                .setTrustedCertificates(trustedCertificates).setTrustAllRPKs().build());
        DTLSConnector dtlsConnector = new DTLSConnector(builder.build());
        CoapEndpoint endpoint = new CoapEndpoint.Builder().setConnector(dtlsConnector).build();
        endpoint.start();
        return endpoint;
    }
}